package com.iretailer.report.quartz;

import com.iretailer.report.init.annotation.BootLoading;
import com.iretailer.report.init.annotation.ExecutionMethod;
import com.iretailer.report.quartz.init.QuartzJobFactory;
import com.iretailer.report.quartz.init.QuartzJobFactoryDisallowConcurrentExecution;
import com.iretailer.report.quartz.model.QuartTask;
import com.iretailer.report.quartz.model.QuartzJobBean;
import com.iretailer.report.service.QuartTaskService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @Auther Bennie
 * @Date 2020/6/15 10:35
 * @Description
 */

@BootLoading
@Component
@Slf4j
public class QuartzService {


    @Value("${loadtask}")
    private boolean loadTask;

    private final SchedulerFactoryBean schedulerFactoryBean;
    private QuartTaskService quartTaskService;

    public QuartzService(SchedulerFactoryBean schedulerFactoryBean, QuartTaskService quartTaskService) {
        this.schedulerFactoryBean = schedulerFactoryBean;
        this.quartTaskService = quartTaskService;
    }


    @ExecutionMethod
    public void quartzTaskLoad() {

        if (loadTask) {
            List<QuartzJobBean> taskList = getTaskList();
            log.info("----- Initializing load timed tasks(初始化加载定时任务) -----");
            taskList.forEach(job -> {
                try {
                    if (addJob(job)) {
                        log.info("----- Initializing task `{}` success -----", job.getJobName());
                    }
                } catch (SchedulerException e) {
                    log.error(e.getMessage(), e);
                }
            });
        }
    }

    /*
     *
     * 查询任务列表
     * @return
     */
    public List<QuartzJobBean> getTaskList() {
        List<QuartzJobBean> jobs = new ArrayList<>();
        List<QuartTask> taskList = quartTaskService.list(null);
        if (taskList != null && taskList.size() > 0) {
            taskList.forEach(it -> {
                QuartzJobBean job = getTask(it);
                if (job != null) {
                    jobs.add(job);
                }
            });
        }
        return jobs;
    }

    /**
     * 查询任务列表
     *
     * @return
     */
    public QuartzJobBean getTask(QuartTask bo) {
        if (bo != null) {
            QuartzJobBean job = new QuartzJobBean();
            job.setJobId(bo.getSpringId());
            job.setJobName(bo.getJobName());
            job.setJobGroup(bo.getJobGroup());
            job.setJobStatus(String.valueOf(bo.getStatus()));
            job.setCronExpression(bo.getCron());
            job.setSpringId(bo.getSpringId());
            job.setIsConcurrent(bo.getConcurrent());
            job.setJobClass(bo.getClazzName());
            job.setMethodName(bo.getMethodName());
            job.setDescription(MessageFormat.format("{0} -> {1} -> {2}", bo.getJobGroup(), bo.getJobName(), bo.getDescription()));
            return job;
        }
        return null;
    }

    public boolean deleteJob(String name, String group) throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        // 先删除旧的 job
        return scheduler.deleteJob(JobKey.jobKey(name, group));
    }

    public boolean addJob(QuartzJobBean job) throws SchedulerException {
        if (job == null || !QuartzJobBean.STATUS_RUNNING.equals(job.getJobStatus())) {
            return false;
        }
        if (!CronExpression.isValidExpression(job.getCronExpression())) {
            log.error("----- 时间表达式错误（{},{})[{}] -----", job.getJobName(), job.getJobGroup(), job.getCronExpression());
            return false;
        } else {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            // 先删除旧的 job
            deleteJob(job.getJobName(), job.getJobGroup());
            // 任务名称和任务组设置规则：    // 名称：task_1 ..    // 组 ：group_1 ..
            TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
            // 不存在，创建一个

            if (null == trigger) {
                //是否允许并发执行
                Class<? extends Job> clazz = QuartzJobBean.CONCURRENT_IS.equals(job.getIsConcurrent()) ? QuartzJobFactory.class : QuartzJobFactoryDisallowConcurrentExecution.class;
                JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).build();
                jobDetail.getJobDataMap().put("scheduleJob", job);
                // 按新的表达式构建一个新的trigger
                trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                scheduler.scheduleJob(jobDetail, trigger);
            } else {     // trigger已存在，则更新相应的定时设置
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                // 按新的trigger重新设置job执行
                scheduler.rescheduleJob(triggerKey, trigger);
            }
        }
        return true;
    }

    public boolean addJob(QuartTask quartTask) throws SchedulerException {
        return addJob(getTask(quartTask));
    }

    public boolean deleteJob(QuartTask quartTask) throws SchedulerException {
        return deleteJob(quartTask.getJobName(), quartTask.getJobGroup());
    }
}
